'''
Created on Dec 2, 2012

@author: quirino
'''
from .defaults import headers, options
from .enums import Method
from .exceptions import TimeoutException
from .utils import merge
from copy import deepcopy, copy
from re import compile
from time import time, sleep

HTTP_RESPONSE_HEAD = compile(r"(?P<version>HTTP\/.*?)\s+(?P<code>\d{3})\s+(?P<message>.*)")

class Request(object):
    '''
    Define the message sent to the replier system
    '''

    def __init__(self, url, method=Method.GET, qs={}, hdr={}, opt={}, 
                 sec=None, auth=None, files={}, data=None):
        '''
        Defines a Request object. Defaults:
         * the request method to GET
         * the header as defined on defaults module
         * the options as defined on defaults module
        '''
        # the request URL
        self.url = url
        # The connection method
        self.method = method
        # The query string parameters
        self.qs = qs
        # the request headers
        self.headers = merge(headers, hdr)
        # the cURL configuration options
        self.options = merge(options, opt)
        # the security configuration as defined on security module
        self.security = sec
        # the authentication method as defined on the authentication module
        self.authentication = auth
        # the files to send when POST or PUT
        self.files = files
        # the raw data to have to send when POST or PUT
        self.data = data
    
    def get_url(self):
        """
        Return a copy of the request URL
        """
        return copy(self.url)
    
    def get_method(self):
        """
        Return a copy of the request method
        """
        return copy(self.method)
    
    def get_qs(self):
        """
        Return a deep copy of the internal query string dictionary
        """
        return deepcopy(self.qs)
    
    def get_headers(self):
        """
        Return the headers as a RFC compliant list.
        """
        return ["%s: %s" % (k,v) for k,v in self.headers.iteritems()]
    
    def get_options(self):
        """
        Return a deep copy of the internal options dictionary
        """
        return deepcopy(self.options)
    
    def get_security(self):
        """
        Return the security handler
        """
        return self.security
    
    def get_authentication(self):
        """
        Return the authentication handler.
        """
        return self.authentication
    
    def get_files(self):
        """
        Return a deep copy of the files dictionary
        """
        return self.files
    
    def get_data(self):
        """
        Return the data to have to send in POST or PUT
        """
        return copy(self.data)
    
class Response(object):
    """
    HTTP response object returned by HTTPConnectionPool.urlopen
    """
    def __init__(self, url, headers, body, info, cookies=None):
        """
        Initializes the response object.
        @param url: the effective URL used to make the HTTP request
        @param headers: the HTTP response headers
        @param body: the HTTP response body
        @param info: the detailed HTTP transaction (request/response) 
        information. Include timings, redirect info 
        @param cookies: the HTTP cookies
        """
        self.url = url
        self.headers = self._build_headers(headers)
        self.body = body
        self.info = info
        # TODO cookies
        
    def _build_headers(self, headers):
        """
        Build the headers map starting from the provided StringIO object
        """
        try :
            buflist = getattr(headers, 'buflist');
        except AttributeError :
            buflist = headers.getvalue().split('\r\n')
        headers = dict()
        for hdr in buflist :
            if hdr is None : continue
            # remove all trailing whitespace
            hdr = str(hdr).rstrip()
            if hdr is "" : continue
            if hdr.startswith("HTTP") :
                try :
                    version, code, message = HTTP_RESPONSE_HEAD.findall(hdr)[0]
                    headers['version'] = version
                    headers['code'] = code
                    headers['message'] = message
                except Exception :
                    continue
            else :
                kv = hdr.split(":", 1)
                headers[kv[0].strip()] = kv[1].strip()
        return headers
    
    def get_body(self):
        """
        Return the response body as a string
        """
        return self.body.getvalue()
    def get_info(self):
        """
        Return the detailed transaction information
        """
        return self.info
    def get_headers(self):
        """
        Return the response headers
        """
        return self.headers
    def get_url(self):
        """
        Return the request URL
        """
        return self.url

class Future(object):
    """
    Simple future implementation class
    """
    def __init__(self):
        self.response = None
        self.exception = None
        self.ready = False
        self.collected = False
    
    def set(self, resp, exc):
        self.response = resp
        self.exception = exc
        self.ready = True
    
    def isready(self):
        return self.ready
    
    def iscollected(self):
        self.collected
    
    def get(self, timeout=-1):
        if timeout<0:
            while not self.ready: sleep(0.1)
        else:
            start = time()
            while not self.ready: 
                if (time()-start)<timeout: 
                    raise TimeoutException(1, "Timeout exceeded")
                sleep(0.1)
        
        self.collected = True
        if self.exception is not None:
            raise self.exception
        else:
            return self.response